﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace API.Models.Repository
{
    public class OutgoingInvoices_Repository : GenericRepository<PartnerDbContext, V_OutgoingInvoices>
    {
        public override void Add(V_OutgoingInvoices entity)
        {
            var documents = this.Find(r =>
                r.DOC_ID == entity.DOC_ID &&
                r.COMPANY_GUID == this.session.COMPANY_GUID);

            if (documents.Any())
                throw new Exception(
                    String.Format("Документ с идентификатором {0} уже был загружен в систему", entity.DOC_ID));

            this.InsertOrUpdate(entity);
        }

        public override IQueryable<V_OutgoingInvoices> Find(System.Linq.Expressions.Expression<Func<V_OutgoingInvoices, bool>> predicate)
        {
            /// Получить данные
            IQueryable<V_OutgoingInvoices> query = _entities.V_OutgoingInvoices
                .Include("COMPANY")
                .Include("CUSTOMER")
                .Include("LOCATION")
                .Include("LINES")
                .Include("LINES.ITEM");

            /// Фильтрация по заданному условию
            if (predicate != null)
                query = query.Where(predicate);

            if (session != null)
                query = query
                    .Where(r => r.COMPANY_GUID == session.COMPANY_GUID);

            return query.AsQueryable();
        }

        public override void Edit(V_OutgoingInvoices entity)
        {
            this.InsertOrUpdate(entity);
        }

        public override void Delete(V_OutgoingInvoices entity)
        {
            var record = _entities.WH_INVOICES.SingleOrDefault(r => 
                r.COMPANY_GUID == session.COMPANY_GUID && 
                r.GUID_RECORD == entity.GUID_RECORD);

            if (record == null)
                throw new Exception("Документ не существует");
            
            _entities.WH_INVOICES.Remove(record);
        }

        public void Recode(Guid INVOICE_GUID)
        {
            this.Context.Database.ExecuteSqlCommand(
                "EXEC [dbo].[USP_SET_INVOICE_MAPPING] @INVOICE_GUID",
                new System.Data.SqlClient.SqlParameter("INVOICE_GUID", INVOICE_GUID));
        }

        private void InsertOrUpdate(V_OutgoingInvoices entity)
        {
            var companiesRepository = new WH_COMPANIES_Repository();
            var locationsRepository = new LOCATIONS_Repository();
            var itemsRepository = new WH_ITEMS_Repository();

            companiesRepository.SetSession(this.session);
            locationsRepository.SetSession(this.session);
            itemsRepository.SetSession(this.session);


            /// Определить значения полей
            /// COMPANY_GUID
            /// CUSTOMER_GUID
            /// LOCATION_GUID
            /// ITEM_GUID

            entity.COMPANY_GUID = this.session.COMPANY_GUID;

            /// Найдем в базе запись
            if (entity.CUSTOMER != null)
            {
                var customer = companiesRepository.Find(r =>
                    r.OWNER_GUID == entity.COMPANY_GUID &&
                    r.EXT_KEY == entity.CUSTOMER.EXT_KEY).SingleOrDefault();

                if (customer != null)
                {
                    entity.CUSTOMER_GUID = customer.GUID_RECORD;
                    entity.CUSTOMER.GUID_RECORD = entity.CUSTOMER_GUID;
                    entity.CUSTOMER.OWNER_GUID = entity.COMPANY_GUID;
                }
                else
                {
                    entity.CUSTOMER_GUID = Guid.NewGuid();
                    entity.CUSTOMER.GUID_RECORD = entity.CUSTOMER_GUID;
                    entity.CUSTOMER.OWNER_GUID = entity.COMPANY_GUID;
                }
            }

            /// Обработка локации
            /// TODO Реализовать корректное определение дефолтной локации
            if (entity.LOCATION != null)
            {
                var location = locationsRepository.Find(r =>
                    r.COMPANY_GUID == entity.COMPANY_GUID &&
                    r.EXT_KEY == entity.LOCATION.EXT_KEY).SingleOrDefault();

                if (location != null)
                {
                    entity.LOCATION_GUID = location.GUID_RECORD;
                    entity.LOCATION.GUID_RECORD = entity.LOCATION_GUID.Value;
                    entity.LOCATION.COMPANY_GUID = entity.COMPANY_GUID;
                }
                else
                {
                    entity.LOCATION_GUID = Guid.NewGuid();
                    entity.LOCATION.GUID_RECORD = entity.LOCATION_GUID.Value;
                    entity.LOCATION.COMPANY_GUID = entity.COMPANY_GUID;
                }
            }
            else
            {
                if (!entity.LOCATION_GUID.HasValue)
                {
                    var location = locationsRepository.Find(r =>
                        r.COMPANY_GUID == entity.COMPANY_GUID
                        && r.IS_DEFAULT
                        ).FirstOrDefault();

                    if (location != null)
                    {
                        entity.LOCATION_GUID = location.GUID_RECORD;
                        entity.LOCATION = location;
                    }
                    else
                    {
                        entity.LOCATION = new WH_LOCATIONS
                        {
                            GUID_RECORD = Guid.NewGuid(),
                            COMPANY_GUID = entity.COMPANY_GUID,
                            EXT_KEY = "XXXXXXX",
                            LOCATION_NAME = "Локация не указана",
                            IS_DEFAULT = true
                        };

                        entity.LOCATION_GUID = entity.LOCATION.GUID_RECORD;

                        locationsRepository.Add(entity.LOCATION);
                        locationsRepository.Save();
                    }
                }
            }

            /// Обновление связанных справочников
            this.InsertOrUpdate<WH_COMPANIES>(entity.CUSTOMER);
            this.InsertOrUpdate<WH_LOCATIONS>(entity.LOCATION);

            if (entity.LINES != null)
            {

                foreach (var line in entity.LINES)
                {
                    if (line.GUID_RECORD == Guid.Empty)
                        line.GUID_RECORD = Guid.NewGuid();

                    line.INVOICE_GUID = entity.GUID_RECORD;

                    if (line.ITEM != null)
                    {
                        var item = itemsRepository.Find(i =>
                                i.COMPANY_GUID == entity.COMPANY_GUID &&
                                i.EXT_KEY == line.ITEM.EXT_KEY).SingleOrDefault();

                        if (item != null)
                        {
                            line.ITEM_GUID = item.GUID_RECORD;
                            line.ITEM.GUID_RECORD = line.ITEM_GUID.Value;
                            line.ITEM.COMPANY_GUID = entity.COMPANY_GUID;
                        }
                        else
                        {
                            line.ITEM_GUID = Guid.NewGuid();
                            line.ITEM.GUID_RECORD = line.ITEM_GUID.Value;
                            line.ITEM.COMPANY_GUID = entity.COMPANY_GUID;
                        }

                        this.InsertOrUpdate<WH_ITEMS>(line.ITEM);
                        this.Save();

                        line.ITEM = null;
                    }
                }
            }

            entity.COMPANY = null;
            entity.CUSTOMER = null;
            entity.LOCATION = null;

            //throw new NotImplementedException();
            this.InsertOrUpdate<V_OutgoingInvoices>(entity);
        }
    }
}